#pragma once
#include <functional>
#include <string>
#include <signal.h>
#include "log.hpp"
#include "1my_socket.hpp"

using func_t = std::function<std::string(std::string&)>;

class TcpServer
{
public:
    TcpServer(uint16_t port, func_t handle)
    : _port(port)
    , _handle(handle)
    {}

    void Init()
    {
        _listen_sock.Socket();
        _listen_sock.Bind(_port);
        _listen_sock.Listen();
        lg(Info, "tcp init");
    }

    void Start()
    {
        signal(SIGCHLD, SIG_IGN);
        signal(SIGPIPE, SIG_IGN);

        while(1)
        {
            struct sockaddr_in peer;
            int afd = _listen_sock.Accept(&peer);
            if(afd == -1)
            {
                continue;
            }
            uint16_t port = ntohs(peer.sin_port);
            char ip[32];
            inet_ntop(AF_INET, &(peer.sin_addr), ip, sizeof(ip));
            lg(Info, "accept ok, afd: %d, port: %d, ip: %s", afd, port, ip);

            if(fork() == 0)
            {
                _listen_sock.Close();

                std::string in_stream;
                while(1)
                {
                    char buffer[1024];
                    int r = read(afd, buffer, sizeof(buffer));
                    if(r > 0)
                    {
                        buffer[r] = 0;
                        in_stream += buffer;

                        while(1)
                        {
                            std::string package = _handle(in_stream);
                            if(package.empty())
                            {
                                break;
                            }
                            lg(Debug, "package: %s", package.c_str());
                            write(afd, package.c_str(), package.size());
                        }
                    }
                    else if(r == 0)
                    {
                        break;
                    }
                    else
                    {
                        break;
                    }
                }
                exit(0);
            }
            
            close(afd);
        }
    }

private:
    uint16_t _port;
    SocketServer _listen_sock;
    func_t _handle;
};